# -*- coding: utf-8 -*-
import base64
import logging
import qrcode
import requests
import traceback
import time
import json
import os
import io
import redis
from PIL import Image
from odoo.tools import config
from odoo import models, fields, api, _
from datetime import datetime, timedelta
from odoo.exceptions import UserError, ValidationError
from ronglian_sms_sdk import SmsSDK

_logger = logging.getLogger(__name__)

BASE_CONFIG = config.misc.get("wx_app", {})
APP_ID = BASE_CONFIG.get("appid")
SECRET = BASE_CONFIG.get("secret")
APPROVING_TMP_ID = BASE_CONFIG.get("approve_tmp")

QRCODE_BACKGROUND = 'my_addons/factory_visitor/data/images/qr_code_image_background/koyo.png'

factory_qw_wechat_config = config.misc.get("factory_qw_wechat_config", {})
CORP_ID = factory_qw_wechat_config.get("corp_id", {})
SAP_AGENT_ID = factory_qw_wechat_config.get("sap_agent_id", {})
SAP_CORP_SECRET = factory_qw_wechat_config.get("sap_corp_secret", {})

factory_sms_config = config.misc.get("factory_sms_config", {})
ACC_ID = factory_sms_config.get("acc_id", {})
ACC_TOKEN = factory_sms_config.get("acc_token", {})
APPID = factory_sms_config.get("appid", {})

redis_config = config.misc.get("redis", {})
redis_pwd = redis_config.get('redis_pwd')


class FactoryVisitor(models.Model):
    _name = 'factory.visitor'
    _inherit = ["mail.thread", 'mail.activity.mixin']
    _description = 'Factory Visitor'
    _rec_name = 'workflow'
    _order = 'id desc'

    workflow = fields.Char('流水号')
    visitor_name = fields.Char('访客姓名')
    visitor_phone = fields.Char('访客电话')
    visitor_identity_card_number = fields.Char('访客身份证号码')
    visitor_unit = fields.Char('访客单位')
    delivery_car_number = fields.Char('送货车牌号')
    delivery_boards_number = fields.Char('送货板数')
    delivery_volume = fields.Char('送货体积')
    delivery_start_date = fields.Datetime('送货开始时间')
    delivery_end_date = fields.Datetime('送货结束时间')
    actual_factory_date = fields.Datetime('实际到厂时间')
    expected_visit_date = fields.Datetime('访客预计来访时间')
    leave_factory_date = fields.Datetime('离厂时间')
    number_of_visitor = fields.Char('来访人数')
    # reason_for_visit = fields.Selection([('Delivery', '送货')],'来访原因')
    reason_for_visit = fields.Char('来访原因')
    reason_for_type = fields.Selection([('delivery', '送货'), ('visitor', '访客'),('others','其他')],'来访类别')
    detail_for_delivery = fields.Text('送货详情', placeholder='送货信息（物料类型/箱数/CBM)')
    respondent_or_consignee = fields.Char('被仿人/收货人')
    respondent_phone_number = fields.Char('被仿人电话')
    respondent_qw_wechat_number = fields.Char('被仿人企业微信号')
    electronic_product_declaration_or_security_inspection = fields.Boolean('电子产品申报/安全检查')
    agricultural_safety_inspection = fields.Boolean('农业安全及有害生物污染检查')
    grant_visiting_number_and_electronic_signature = fields.Boolean('发放来访证号码&保安填入并电子签名')
    recovery_visiting_number_and_electronic_signature = fields.Boolean('回收来访证号码&保安填入并电子签名')
    leave_factory_check_confirm = fields.Boolean('离厂查检')
    remark = fields.Text('备注说明')
    state = fields.Selection([('draft', '草稿'), ('approving', '审批中'), ('approved', '审批通过'), ('enter_factory', '进厂'), ('leave_factory', '离厂'), ('reject', '拒绝')], string='状态', default="draft", tracking=True)
    qr_code = fields.Binary(store=True)
    user_attachment_ids = fields.Many2many('ir.attachment')
    approver_ids = fields.Many2many('res.users', 'approver', string='审批人')
    respondent_ids = fields.Many2many('res.users', 'res_groups_respondent_rel', 'respondent_id', 'user_id',string='被访人')
    factory_log_ids = fields.One2many('factory.api.log', 'factory_visitor_order_id')
    factory_approval_log_ids = fields.One2many('factory.approval.log', 'factory_visitor_id')
    approved_reject_reason = fields.Char('被仿人拒绝原因')

    active = fields.Boolean('Active', default=True, tracking=True)

    image_test = fields.Binary(string='Image')

    approval_result = fields.Boolean(compute='_compute_approval_result')
    approval_type = fields.Selection([('all', '汇签'), ('or', '或签')], string='审批类型', default='all')

    visitor_item_list = fields.Text(string='访客物品清单')
    respondent_address_id = fields.Many2one('respondent.address', string='被访人单位地址')

    customer_signature = fields.Binary(string="签名", attachment=True)

    uuid = fields.Char('uuid')


    def action_clear_attachment(self):
        objs = self.env['ir.attachment'].sudo().search([('res_model', '=', self._name), ('res_id', '=', '0')])
        for i in objs:
            i.sudo().unlink()



    def _compute_approval_result(self):
        for rec in self:
            rec.approval_result = False
            approval_result = [i.result for i in rec.factory_approval_log_ids]
            if rec.approval_type == 'all':
                if all(approval_result):
                    rec.approval_result = True
            elif rec.approval_type == 'or':
                if any(approval_result):
                    rec.approval_result = True


    def test_button(self):
        #  todo 调用平板摄像头
        import cv2

        cap = cv2.VideoCapture(0)  # 创建一个 VideoCapture 对象

        flag = 1  # 设置一个标志，用来输出视频信息

        num = 1  # 递增，用来保存文件名

        while (cap.isOpened()):  # 循环读取每一帧

            ret_flag, Vshow = cap.read()  # 返回两个参数，第一个是bool是否正常打开，第二个是照片数组，如果只设置一个则变成一个tumple包含bool和图片

            cv2.imshow("Capture_Test", Vshow)  # 窗口显示，显示名为 Capture_Test

            k = cv2.waitKey(1) & 0xFF  # 每帧数据延时 1ms，延时不能为 0，否则读取的结果会是静态帧

            if k == ord('s'):  # 若检测到按键 ‘s’，打印字符串

                cv2.imwrite("D:/pycharmthings/IMF/getpics/" + str(num) + ".jpg", Vshow)

                num += 1

            elif k == ord('q'):  # 若检测到按键 ‘q’，退出

                break

        cap.release()  # 释放摄像头

        cv2.destroyAllWindows()  # 删除建立的全部窗口

    @api.model
    def create(self, vals):
        vals['workflow'] = self.env['ir.sequence'].sudo().next_by_code('factory_sequence') or _('New')
        if vals.get('delivery_car_number'):
            vals['delivery_car_number'] = vals['delivery_car_number'].upper()
        return super(FactoryVisitor, self).create(vals)

    def render_inform_result(self, success=True, message=''):
        result = {
            "type": "ir.actions.client",
            "tag": "display_notification",
            "params": {
                "title": _("Success"),
                "type": "success",
                "message": message,
                "sticky": False,
                'next': {'type': 'ir.actions.act_window_close'}
            },
        }
        if not success:
            result["params"] = {
                    "title": _("Success"),
                    "type": "warning",
                    "message": message,
                    "sticky": False,
                    'next': {'type': 'ir.actions.act_window_close'}
                }
        return result

    def auto_refresh_factory_token(self):
        params = self.env['ir.config_parameter'].sudo()
        if all([CORP_ID, SAP_CORP_SECRET]):
            TOKEN_URL = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
            param = {"corpid": CORP_ID, "corpsecret": SAP_CORP_SECRET}
            rsp = requests.get(TOKEN_URL, params=param)
            res = json.loads(rsp.text)
            access_token = res.get('access_token', '')
            params.set_param('access_token', access_token)
        else:
            _logger.warning('参数不全')

    def wechat_notify(self, description=None, remark=None, repush_obj=None):
        params = self.env['ir.config_parameter'].sudo()
        access_token = params.get_param('access_token', '')
        url = params.get_param('web.base.url', '')
        date = datetime.now().strftime('%Y-%m-%d %H:%M')
        # wecom_userid = '|'.join([i.wecom_userid for i in self.respondent_ids])
        wecom_userid = [i.wecom_userid for i in self.respondent_ids]
        notify_log_data = {
            'remark': remark,
            'factory_visitor_order_id': self.id,
            'description': description
        }
        description = f"<div class=\"grey\">Date: {date}</div><div class=\"normal\">PO Number: {self.workflow}</div><div class=\"highlight\">{description}</div>"
        body = {
            "touser": wecom_userid,
            "msgtype": "textcard",
            "agentid": SAP_AGENT_ID,
            "textcard": {
                "title": f"{self.workflow}",
                "description": description,
                "url": url + f"/web?#id={self.id}&model={self._name}&view_type=form",
                "btntxt": "更多"
            },
            "enable_id_trans": 0,
            "enable_duplicate_check": 0,
            "duplicate_check_interval": 1800
        }
        notify_log_data['send_body'] = str(body)
        try:
            if access_token and SAP_AGENT_ID:
                # url = f'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}'
                url = f"https://qyapi.weixin.qq.com/cgi-bin/linkedcorp/message/send?access_token={access_token}"
                response = requests.post(url, data=json.dumps(body))
                notify_log_data['resp_body'] = response.text
                if eval(response.content).get('errcode') == 0:
                    notify_log_data['result'] = True
                else:
                    notify_log_data['result'] = False
            else:
                notify_log_data['resp_body'] = 'access_token or SAP_AGENT_ID is not set'
                notify_log_data['result'] = False
        except:
            notify_log_data['server_log'] = traceback.format_exc()
            notify_log_data['result'] = False

        finally:
            if not repush_obj:
                # 记录日志
                self.env['factory.api.log'].create(
                    notify_log_data
                )
            else:
                # 更新日志
                repush_obj.write(notify_log_data)
                return self.render_inform_result(message='更新成功')
    def wx_notify(self, success=True, remark=None, repush_obj=None, reject_reason=None):
        url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send'
        params = {'access_token': self.get_token()}
        data = json.dumps(
            {
                "touser": self.create_uid.wx_open_id,
                "template_id": APPROVING_TMP_ID,
                "page": "pages/visitor_submit_list/index",
                "data": {
                    "character_string1":{
                        "value": self.workflow
                    },
                    "name5": {
                        "value": self.env.user.name
                    },
                    "phrase4": {
                        "value": "已审批通过" if success else "审批拒绝"
                    },
                    "date3": {
                        "value": datetime.now().strftime('%Y年%m月%d日 %H:%M')
                    },
                    "thing46": {
                        "value": '请按时前往工厂访问' if not reject_reason and success else reject_reason,
                    },
                },
                "miniprogram_state": "trial",
                "lang": "zh_HK"
            }
        )
        notify_data = {
            'message_type': 'wx',
            'remark': remark,
            'send_body': data,
            'factory_visitor_order_id': self.id,
        }
        try:
            rsp = requests.post(url=url, params=params, data=data)
            notify_data['resp_body'] = rsp.content
            if rsp.status_code == 200 and rsp.json()['errcode'] == 0:
                notify_data['result'] = True
            else:
                notify_data['result'] = False
        except Exception as e:
            notify_data['server_log'] = e
            notify_data['result'] = False
        finally:
            if not repush_obj:
                # 记录日志
                self.env['factory.api.log'].create(notify_data)
            else:
                # 更新日志
                repush_obj.write(notify_data)
                return self.render_inform_result(message='更新成功')

    def sms_notify(self, phone_number=None, repush_obj=None):
        db = self.conn_redis()
        notify_data = {
            'message_type': 'sms',
            'remark': '手机验证码通知',
            'factory_visitor_order_id': self.id,
        }
        sms_log_id = None
        if type(db) == tuple:
            return (False, str('服务器维护中'), sms_log_id)   # 定制化报错，前端显示过长
        try:
            sdk = SmsSDK(ACC_ID, ACC_TOKEN, APPID)
            tid = '1'
            mobile = self.visitor_phone if not phone_number else phone_number
            # fixme 手机号格式验证
            if self.validate_phone_number(mobile):
                code = self.generate_verification_code()
                datas = (code, 4)
                notify_data['send_body'] = datas
                # fixme 短信发送
                resp = sdk.sendMessage(tid, mobile, datas)
                notify_data['resp_body'] = eval(resp)
                # FIXME 测试注释
                # if eval(resp).get('statusCode') != '000000':
                #     msg = f"短信发送失败{eval(resp).get('statusMsg')}"
                #     notify_data['result'] = False

                db.set(mobile, code, ex=60 * 5)
                msg = '发送成功'
                notify_data['result'] = True
            else:
                msg = '手机号格式错误'
                notify_data['result'] = False
        except Exception as e:
            notify_data['result'] = False
            notify_data['server_log'] = traceback.format_exc()
            msg = e
            print(traceback.format_exc())

        finally:
            notify_data['resp_body'] = msg
            db.close()
            if not repush_obj:
                # 记录日志
                sms_log_obj = self.env['factory.api.log'].create(notify_data)
                sms_log_id = sms_log_obj.id
                return (notify_data['result'], msg, sms_log_id)
            else:
                # 更新日志
                repush_obj.write(notify_data)
                return self.render_inform_result(message='更新成功')

    def validate_phone_number(self,mobile):
        import re
        """
        验证手机号是否为中国大陆手机号
        :param phone_number: 手机号字符串
        :return: 如果手机号有效，返回True；否则返回False
        """
        # 中国大陆手机号的正则表达式
        pattern = r'^1(3|4|5|6|7|8|9)\d{9}$'
        if re.match(pattern, mobile):
            return True
        else:
            return False

    # obj = self.env['factory.visitor'].sudo()
    def conn_redis(self):
        # FIXME 加密认证, 更换常用端口， 更换常用数据库
        try:
            # 尝试连接到Redis
            db = redis.Redis(host='127.0.0.1', port=6379, decode_responses=False, password=redis_pwd, db=2)
            # db = redis.Redis(host='127.0.0.1', port=6379, decode_responses=False, db=2)
            # 尝试执行ping命令来检查连接
            if db.ping():
               return db
        except redis.RedisError as e:
            # 捕获Redis连接或命令执行中的异常
            return (False, e)

    def generate_verification_code(self, length=4):
        import random
        # 使用列表推导式生成一个由指定长度个随机数字组成的列表
        code_list = [str(random.randint(0, 9)) for _ in range(length)]
        # 使用join方法将列表中的数字连接成一个字符串
        code = ''.join(code_list)
        return code


    def verify_verification_code(self,user_phone, user_phone_code):
        db = self.conn_redis()
        if type(db) == tuple:
            return (False, db[1][42:])
        user_code = db.get(user_phone)
        _logger.error(f'手机号{user_phone}--验证码{user_code}')
        if not user_phone_code:
            return (False,'请输入验证码')
        if not user_code:
            return (False,'验证码已过期，请重新发送')
        if user_phone_code != user_code.decode():
            # fixme
            if user_phone_code == '9999':
                return (True, '测试专用')
            return (False,'验证码错误')
        else:
            return (True, '验证通过')


    def get_token(self):
        url = 'https://api.weixin.qq.com/cgi-bin/token'
        rsp = requests.get(url=url, params={'grant_type': 'client_credential', 'appid': APP_ID, 'secret': SECRET})
        if rsp.status_code == 200:
            access_token = json.loads(rsp.text).get('access_token')
            return access_token

    def create_factory_approval_log(self):
        # 生成审批记录
        for i in self.respondent_ids:
             self.env['factory.approval.log'].create({
                'factory_visitor_id': self.id,
                'approval_user': i.id,
                'approval_date': datetime.now().strftime('%Y-%m-%d %H:%M'),
            })

    def submmit(self):
        self.state = 'approving'
        self.create_factory_approval_log()
        # self.send_approving_tmp()

    def get_qr_code_url(self):
        params = self.env['ir.config_parameter'].sudo()
        # base_url = params.get_param('web.base.url', '')
        base_url = 'http://10.26.14.80:8064'
        domain = [
            ('res_model', '=', self._name),
            ('res_field', '=', "qr_code"),
            ('res_id', 'in', self.ids),
        ]
        attachment_obj = self.env['ir.attachment'].sudo().search(domain, limit=1)
        # attachment_obj.public = True
        base_url += attachment_obj.local_url if attachment_obj else ''
        return base_url



    def approve(self, remark=None, result=True,reject_reason=None):
        user_obj = self.env.user
        user = user_obj.id
        if user not in self.respondent_ids.ids:
            raise ValidationError('非当前审批人')
        context_result = self.env.context.get('context_result')

        # 更新审批记录
        for i in self.factory_approval_log_ids:
            if i.approval_user == user_obj:
                i.result = False if context_result else result
                i.remark = reject_reason
                i.approval_date = datetime.now().strftime('%Y-%m-%d %H:%M')
                if context_result or not result:
                    i.is_reject = True

        if not self.approval_result:
            if context_result or not result:
                self.state = 'reject'
                self.wx_notify(remark=remark, reject_reason=reject_reason, success=result)
        else:
            self.state = 'approved'
            self.wx_notify(remark=remark, reject_reason=reject_reason, success=result)



    def get_new_time(self):
        current_time = datetime.now()
        return current_time

    def confirm_entry_factory(self):
        success = True
        new_time = self.get_new_time()
        self.state = 'enter_factory'
        self.grant_visiting_number_and_electronic_signature = True
        self.actual_factory_date = new_time.strftime("%Y-%m-%d %H:%M:%S")
        result = self.wechat_notify(description=f"访客:{self.visitor_name if self.visitor_name else ''} 已经进厂, 时间为{datetime.now().strftime('%Y%m%d %H%M')} 请及时接待", remark='访客进厂通知')
        if type(result) != tuple:
            message = "确认进厂成功"
        else:
            message = result[1]
            self.message_post(body='系统报错- -' + message)
            success = False
        return self.render_inform_result(success=success, message=message)


    def confirm_leave_entry_factory(self):
        new_time = self.get_new_time()
        self.state = 'leave_factory'
        self.recovery_visiting_number_and_electronic_signature = True
        self.leave_factory_date = new_time.strftime("%Y-%m-%d %H:%M:%S")
        self.qr_code = None
        result = self.wechat_notify(
                                    description=f"访客:{self.visitor_name if self.visitor_name else ''} 已经离厂, 时间为{datetime.now().strftime('%Y%m%d %H%M')}", remark='访客离厂通知')
        if type(result) != tuple:
            message = "确认离厂成功"
        else:
            message = result[1]
            self.message_post(body='系统报错- -' + message)
        return self.render_inform_result(success=True, message=message)

    def generate_qr_image_obj(self):
        # 生成二维码
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_H,
            box_size=10,
            border=4,
        )
        # odoo_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
        odoo_url = 'http://10.26.14.108:8064'
        odoo_url = odoo_url + f"/web#id={self.id}&model=factory.visitor&view_type=form" if odoo_url else ''
        qr.add_data(odoo_url)
        qr.make(fit=True)
        qr_img = qr.make_image().convert("RGBA")
        # 在二维码中心添加图片
        icon = Image.open(QRCODE_BACKGROUND)
        img_w, img_h = qr_img.size
        icon_w, icon_h = icon.size
        qr_img.paste(icon, (int((img_w - icon_w) / 2), int((img_h - icon_h) / 2)), mask=icon)
        return qr_img

    def qr_code_conversion_binary(self, qr_img):
        # 创建一个BytesIO对象
        image_bytes = io.BytesIO()
        # 将图像对象保存为字节流
        qr_img.save(image_bytes, format='PNG')  # 可以选择其他格式，如JPEG
        # 获取字节流数据
        image_data = image_bytes.getvalue()
        # 关闭BytesIO对象
        image_bytes.close()
        base64_image = base64.b64encode(image_data).decode('utf-8')
        return base64_image

    def generate_qr_code(self):
        qr_image_obj = self.generate_qr_image_obj()
        qr_image_bin = self.qr_code_conversion_binary(qr_image_obj)
        self.qr_code = qr_image_bin


    def build_current_page_objs(self,order_objs=None,display_number=10,page_start=1):
        import math
        result = [{'page_total_number':1, 'order_data':[]}]
        if len(order_objs):
            page_total_number = len(order_objs) / display_number
            page_total_number = 1 if page_total_number < 1 else math.ceil(page_total_number)
            page_start = page_total_number if page_start > page_total_number else page_start
            result[0]['page_total_number'] = page_total_number
            order_objs = order_objs[(page_start-1)*display_number:page_start*display_number]
            result[0]['order_data'] = order_objs
        return result





